
from vBaum import *
from random import *
from math import *


rand = Random()
rand.seed(12345)

def randVec(offsetMin, offsetMax):
	x = rand.choice([rand.uniform(-offsetMax,-offsetMin), rand.uniform(offsetMin, offsetMax)])
	y = rand.choice([rand.uniform(-offsetMax,-offsetMin), rand.uniform(offsetMin, offsetMax)])
	z = rand.choice([rand.uniform(-offsetMax,-offsetMin), rand.uniform(offsetMin, offsetMax)])
	return Vector3(x,y,z)

def createAxonSphere(randMul, ripplesMul, ripplesOffset, fPos):
	posScaled = (fPos-0.5)*2
	normalizedRadius = 0.45 + 0.55*(posScaled**2)
	offset = min(abs(sin((fPos+ripplesOffset)*ripplesMul*pi)), 0.5) * 2.5
	return Sphere (min(4.0, max(1.2, normalizedRadius*randMul*offset)))
	
def connectNeurons(p1, p2):
	numMids = rand.randint(1,3)
	offset = 1.0 / (1.0+numMids)
	curr = offset
	mids = []	
	for i in range(0, numMids):
		p = randVec(0, 4)	
		ref = (p1*curr) + (p2*(1-curr))
		mids = mids + [ref+p]
		curr = curr + offset
		
	mids = sorted(mids, key = lambda p: p.squaredDistance(p1)) 
	splinePoints = [p1] + mids + [p2]
	spline = Spline(splinePoints, False)
	randMul = rand.uniform(2.5,3.5)
	ripplesMul = rand.randint(4,5)
	ripplesOffset = rand.uniform(0, 0.2)
	axon = spline.extrudeDynamic(lambda fPos: createAxonSphere(randMul, ripplesMul, ripplesOffset, fPos))
	return axon
		
knots = Volume()

def minSquaredDistance(p, points):
	min = 99999999
	for p2 in points:
		sDist = p.squaredDistance(p2)
		if (sDist < min): min = sDist
	return min
	
def randVecWithMinDist(points, min, max, minDist):
	p = randVec(min, max)
	while (minSquaredDistance(p, points) < minDist):
		p = randVec(min, max)	
	return p

points = []
for i in range(0, 150):
	p = randVecWithMinDist(points, 0, 150, 1600)
	points.append(p)

pointsAndNeighbors = []	
for p in points:
	pointsAndNeighbors.append((p, []))
	
for p, neighbors in pointsAndNeighbors:
	sphere = Sphere(rand.uniform(6,8))
	sphere.setPosition(p)
	knots = knots.union(sphere)		
	maxConnects = rand.randint(2,5)
	sortedNeighbors = sorted(pointsAndNeighbors, key = lambda p2: p.squaredDistance(p2[0]))
	sortedNeighbors.pop(0)
	for p2, neighbors2 in sortedNeighbors:
		if maxConnects > 0 and neighbors2.count(p)==0:
			knots = knots.union(connectNeurons(p, p2))
			neighbors.append(p2)		
		maxConnects = maxConnects-1	

knots.exportAsObj("brain", 25)
